package com.tal.bcc.pad.cloud.utils;




import java.io.IOException;
import java.net.URLEncoder;
import java.util.*;

import com.tal.bcc.pad.cloud.utils.sign.Base64;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

public class SignatureSDK {
    public static final String APPLICATION_JSON = "application/json";
    public static final String APPLICATION_X_WWW_FORM_URLENCODED = "application/x-www-form-urlencoded";
    public static final String BINARY = "application/octet-stream";
    public static final String INPUT_STREAM_ENTITY = "inputStreamEntity";
    public static final String MULTIPART_FORM_DATA = "multipart/form-data";
    public static final String MULTIPART_BODY = "multipartBody";

    private static final String CHARSET_UTF8 = "utf8";
    private static final String REQUEST_BODY = "request_body";

    /**
     * 组合URL和Body参数，并计算签名
     *
     * @param access_key_id
     * @param access_key_secret
     * @param timestamp
     * @param urlParam
     * @throws Exception
     */
    public static void getSignature(String access_key_id, String access_key_secret, String timestamp,
                                    Map<String, Object> urlParam, Map<String, Object> bodyParams, RequestMethod requestMethod, String contentType) {
        try {
            urlParam.put("access_key_id", access_key_id);

            String signature_nonce = UUID.randomUUID().toString();
            urlParam.put("signature_nonce", signature_nonce);
            urlParam.put("timestamp", timestamp);

            Map<String, Object> signParams = new HashMap<>(urlParam);

            if (requestMethod != null) {
                if ((requestMethod.equals(RequestMethod.POST) || requestMethod.equals(RequestMethod.PATCH) || requestMethod.equals(RequestMethod.PUT))
                        && (APPLICATION_JSON.equals(contentType) || APPLICATION_X_WWW_FORM_URLENCODED.equals(contentType))) {

                    if (XesStringUtils.isEmpty(contentType)) {
                        throw new Exception("参数contentType不能为空");
                    }
                    if (APPLICATION_X_WWW_FORM_URLENCODED.equals(contentType)) {
//                    ArrayList<BasicNameValuePair> list = new ArrayList<BasicNameValuePair>();
//                    bodyParams.forEach((key, value) -> list.add(new BasicNameValuePair(key,  new Gson().toJson(value))));
//                    //按application/x-www-form-urlencoded格式化request body
//                    String requestBodyStr = URLEncodedUtils.format(list, CHARSET_UTF8);
//                    if(StringUtils.isNotEmpty(requestBodyStr)){
//                        signParams.put(REQUEST_BODY,requestBodyStr);
//                    }
                    } else {
                        signParams.put(REQUEST_BODY, bodyParams);
                    }
                }
            }

            String signStr = generate(signParams, access_key_secret);
            signStr = URLEncoder.encode(signStr, CHARSET_UTF8);
            urlParam.put("signature", signStr);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    /**
     * 获取签名
     *
     * @param parameter
     * @param accessKeySecret
     * @return
     * @throws Exception
     */
    private static String generate(Map<String, Object> parameter, String accessKeySecret) throws Exception {
        String signString = generateSignString(parameter);
        byte[] signBytes = hmacSHA1Signature(accessKeySecret + "&", signString);
        return newStringByBase64(signBytes);
    }


    /**
     * 对parameter进行排序
     *
     * @param params
     * @return
     * @throws IOException
     */
    private static String generateSignString(Map<String, Object> params) throws IOException {
        TreeMap<String, Object> sortParams = new TreeMap<>(params);
        return generateQueryString(sortParams);
    }

    public static String newStringByBase64(byte[] bytes) {
        if (bytes == null || bytes.length == 0) return null;
        return Base64.encodeToString(bytes, Base64.NO_WRAP);
    }

    /**
     * 对params进行format
     *
     * @param params
     * @return
     */
    public static String generateQueryString(Map<String, Object> params) {
        StringBuilder paramsStr = new StringBuilder();
        for (Map.Entry<String, Object> entry : params.entrySet()) {
            paramsStr.append(entry.getKey());
            paramsStr.append("=");
            Object val = entry.getValue();
            paramsStr.append(val instanceof String ? val : JsonUtil.toJson(val));
            paramsStr.append("&");
        }
        paramsStr.deleteCharAt(paramsStr.length() - 1);
        return paramsStr.toString();
    }


    /**
     * 计算签名
     *
     * @param secret
     * @param baseString
     * @return
     * @throws Exception
     */
    private static byte[] hmacSHA1Signature(String secret, String baseString) throws Exception {
        Mac mac = Mac.getInstance("HmacSHA1");
        SecretKeySpec keySpec = new SecretKeySpec(secret.getBytes("utf8"), "utf8");
        mac.init(keySpec);
        return mac.doFinal(baseString.getBytes("utf8"));
    }


    /**
     * URL参数format
     *
     * @param params URL参数
     * @return
     */
    public static String urlParamsFormat(Map<String, Object> params) {
        if (params == null) return null;
        return generateQueryString(params);
    }

}
